package com.gitee.fastmybatis.core.query;

import com.gitee.fastmybatis.core.query.expression.BetweenValue;
import com.gitee.fastmybatis.core.query.expression.ValueConvert;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * and 条件
 * @author thc
 */
public interface ConditionAnd<T> {

    Condition getCondition();

    /**
     * 添加等于条件
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T eq(String columnName, Object value) {
        getCondition().eq(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加等于条件
     * <pre>
     *     query.eq(StringUtils.hasText(name), "name", name);
     *     等同于：
     *     if (StringUtils.hasText(name)) {
     *         query.eq("name", name);
     *     }
     * </pre>
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T eq(boolean expression, String columnName, Object value) {
        if (expression) {
            eq(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加不等于条件
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T notEq(String columnName, Object value) {
        getCondition().notEq(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加不等于条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T notEq(boolean expression, String columnName, Object value) {
        if (expression) {
            notEq(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加大于条件,>
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T gt(String columnName, Object value) {
        getCondition().gt(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加大于条件,>
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T gt(boolean expression, String columnName, Object value) {
        if (expression) {
            gt(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加大于等于条件,>=
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T ge(String columnName, Object value) {
        getCondition().ge(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加大于等于条件,>=
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T ge(boolean expression, String columnName, Object value) {
        if (expression) {
            ge(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加小于条件,<
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T lt(String columnName, Object value) {
        getCondition().lt(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加小于条件,<
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T lt(boolean expression, String columnName, Object value) {
        if (expression) {
            lt(columnName, value);
        }
        return (T) this;
    }

    /**
     * 小于等于,<=
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T le(String columnName, Object value) {
        getCondition().le(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式小于等于条件,<=
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T le(boolean expression, String columnName, Object value) {
        if (expression) {
            le(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加两边模糊查询条件，两边模糊匹配，即name like '%value%'
     *
     * @param columnName 数据库字段名
     * @param value      值,不需要加%
     * @return 返回Query对象
     * @see #likeLeft(String, String) 左边模糊匹配
     * @see #likeRight(String, String) 右边模糊匹配
     */
    default T like(String columnName, String value) {
        getCondition().like(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加两边模糊查询条件，两边模糊匹配，即name like '%value%'
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值,不需要加%
     * @return 返回Query对象
     * @see #likeLeft(boolean, String, String) 左模糊
     * @see #likeRight(boolean, String, String) 右模糊
     */
    default T like(boolean expression, String columnName, String value) {
        if (expression) {
            like(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加左模糊查询条件，左边模糊匹配，即name like '%value'
     *
     * @param columnName 数据库字段名
     * @param value      值,不需要加%
     * @return 返回Query对象
     */
    default T likeLeft(String columnName, String value) {
        getCondition().likeLeft(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加左模糊查询条件，左边模糊匹配，即name like '%value'
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值,不需要加%
     * @return 返回Query对象
     */
    default T likeLeft(boolean expression, String columnName, String value) {
        if (expression) {
            likeLeft(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加右模糊查询条件，右边模糊匹配，即name like 'value%'。mysql推荐用这种
     *
     * @param columnName 数据库字段名
     * @param value      值,不需要加%
     * @return 返回Query对象
     */
    default T likeRight(String columnName, String value) {
        getCondition().likeRight(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加右模糊查询条件，右边模糊匹配，即name like 'value%'。mysql推荐用这种
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值,不需要加%
     * @return 返回Query对象
     */
    default T likeRight(boolean expression, String columnName, String value) {
        if (expression) {
            likeRight(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加IN条件
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T in(String columnName, Collection<?> value) {
        getCondition().in(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加IN条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T in(boolean expression, String columnName, Collection<?> value) {
        if (expression) {
            in(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加IN条件
     *
     * @param columnName   数据库字段名
     * @param value        值
     * @param valueConvert 转换
     * @return 返回Query对象
     */
    default <E> T in(String columnName, Collection<E> value, ValueConvert<E> valueConvert) {
        getCondition().in(columnName, value, valueConvert);
        return (T) this;
    }

    /**
     * 根据表达式添加IN条件
     *
     * @param expression   表达式，当为true时添加条件
     * @param columnName   数据库字段名
     * @param value        值
     * @param valueConvert 转换
     * @return 返回Query对象
     */
    default <E> T in(boolean expression, String columnName, Collection<E> value, ValueConvert<E> valueConvert) {
        if (expression) {
            in(columnName, value, valueConvert);
        }
        return (T) this;
    }

    /**
     * 添加IN条件
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T in(String columnName, Object[] value) {
        getCondition().in(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加IN条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T in(boolean expression, String columnName, Object[] value) {
        if (expression) {
            in(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加not in条件
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T notIn(String columnName, Collection<?> value) {
        getCondition().notIn(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加not in条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T notIn(boolean expression, String columnName, Collection<?> value) {
        if (expression) {
            notIn(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加not in条件
     *
     * @param columnName   数据库字段名
     * @param value        值
     * @param valueConvert 转换器
     * @return 返回Query对象
     */
    default <E> T notIn(String columnName, Collection<E> value, ValueConvert<E> valueConvert) {
        getCondition().notIn(columnName, value, valueConvert);
        return (T) this;
    }

    /**
     * 根据表达式添加not in条件
     *
     * @param expression   表达式，当为true时添加条件
     * @param columnName   数据库字段名
     * @param value        值
     * @param valueConvert 转换器
     * @return 返回Query对象
     */
    default <E> T notIn(boolean expression, String columnName, Collection<E> value, ValueConvert<E> valueConvert) {
        if (expression) {
            notIn(columnName, value, valueConvert);
        }
        return (T) this;
    }

    /**
     * 添加not in条件
     *
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T notIn(String columnName, Object[] value) {
        getCondition().notIn(columnName, value);
        return (T) this;
    }

    /**
     * 根据表达式添加not in条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param value      值
     * @return 返回Query对象
     */
    default T notIn(boolean expression, String columnName, Object[] value) {
        if (expression) {
            notIn(columnName, value);
        }
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param columnName 数据库字段名
     * @param startValue 起始值
     * @param endValue   结束值
     * @return 返回Query对象
     */
    default T between(String columnName, Object startValue, Object endValue) {
        getCondition().between(columnName, startValue, endValue);
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param startValue 起始值
     * @param endValue   结束值
     * @return 返回Query对象
     */
    default T between(boolean expression, String columnName, Object startValue, Object endValue) {
        if (expression) {
            between(columnName, startValue, endValue);
        }
        return (T) this;
    }

    /**
     * 添加between条件
     * <pre>
     * {@literal
     * Object[] arr = new Object[]{1, 100};
     * query.between(arr);
     * }
     * </pre>
     *
     * @param values 存放起始值、结束值，只能存放2个值，values[0]表示开始值，value[1]表示结束值
     * @return 返回Query对象
     */
    default T between(String columnName, Object[] values) {
        getCondition().between(columnName, values);
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param values     存放起始值、结束值，只能存放2个值，values[0]表示开始值，value[1]表示结束值
     * @return 返回Query对象
     */
    default T between(boolean expression, String columnName, Object[] values) {
        if (expression) {
            between(columnName, values);
        }
        return (T) this;
    }

    /**
     * 添加between条件
     * <pre>
     * {@literal
     * query.between(Arrays.asList(1, 100));
     * }
     * </pre>
     *
     * @param values 存放起始值、结束值，只能存放2个值
     * @return 返回Query对象
     */
    default T between(String columnName, List<?> values) {
        getCondition().between(columnName, values);
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param columnName 数据库字段名
     * @param values     存放起始值、结束值，只能存放2个值
     * @return 返回Query对象
     */
    default T between(boolean expression, String columnName, List<?> values) {
        if (expression) {
            between(columnName, values);
        }
        return (T) this;
    }

    /**
     * 添加between条件
     * <pre>
     * {@literal
     * query.between(new BetweenValue(1, 100));
     * }
     * </pre>
     *
     * @param betweenValue 起始值、结束值包装对象
     * @return 返回Query对象
     */
    default T between(String columnName, BetweenValue betweenValue) {
        getCondition().between(columnName, betweenValue);
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param expression   表达式，当为true时添加条件
     * @param columnName   数据库字段名
     * @param betweenValue 存放起始值、结束值，只能存放2个值
     * @return 返回Query对象
     */
    default T between(boolean expression, String columnName, BetweenValue betweenValue) {
        if (expression) {
            between(columnName, betweenValue);
        }
        return (T) this;
    }

    /**
     * 添加自定义sql条件
     *
     * @param sql 自定义sql
     * @return 返回Query对象
     */
    default T sql(String sql) {
        getCondition().sql(sql);
        return (T) this;
    }

    /**
     * 根据表达式添加自定义sql条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param sql        自定义sql
     * @return 返回Query对象
     */
    default T sql(boolean expression, String sql) {
        if (expression) {
            sql(sql);
        }
        return (T) this;
    }

    /**
     * 添加自定义sql条件
     *
     * @param sqlFormat SQL模板，参数值使用?代替，如：<code>username = ? and nickname like '%?%'</code>
     * @param args      参数
     * @return 返回Query对象
     */
    default T sql(String sqlFormat, Object... args) {
        getCondition().sql(sqlFormat, args);
        return (T) this;
    }

    /**
     * 根据表达式添加自定义sql条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param sqlFormat  SQL模板，参数值使用?代替，如：<code>username = ? and nickname like '%?%'</code>
     * @param args       参数
     * @return 返回Query对象
     */
    default T sql(boolean expression, String sqlFormat, Object... args) {
        if (expression) {
            sql(sqlFormat, args);
        }
        return (T) this;
    }

    /**
     * 添加字段不为null的条件
     *
     * @param column 数据库字段名
     * @return 返回Query对象
     */
    default T notNull(String column) {
        return this.sql(column + " IS NOT NULL");
    }

    /**
     * 根据表达式添加字段不为null的条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param column     数据库字段名
     * @return 返回Query对象
     */
    default T notNull(boolean expression, String column) {
        if (expression) {
            notNull(column);
        }
        return (T) this;
    }

    /**
     * 添加字段是null的条件
     *
     * @param column 数据库字段名
     * @return 返回Query对象
     */
    default T isNull(String column) {
        return this.sql(column + " IS NULL");
    }

    /**
     * 根据表达式添加字段是null的条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param column     数据库字段名
     * @return 返回Query对象
     */
    default T isNull(boolean expression, String column) {
        if (expression) {
            isNull(column);
        }
        return (T) this;
    }

    /**
     * 添加不为空字符串条件
     *
     * @param column 数据库字段名
     * @return 返回Query对象
     */
    default T notEmpty(String column) {
        return this.sql(column + " IS NOT NULL AND " + column + " <> '' ");
    }

    /**
     * 根据表达式添加不为空字符串条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param column     数据库字段名
     * @return 返回Query对象
     */
    default T notEmpty(boolean expression, String column) {
        if (expression) {
            notEmpty(column);
        }
        return (T) this;
    }

    /**
     * 添加空字段条件，null或者空字符串
     *
     * @param column 数据库字段名
     * @return 返回Query对象
     */
    default T isEmpty(String column) {
        return this.sql(column + " IS NULL OR " + column + " = '' ");
    }

    /**
     * 根据表达式添加空字段条件，null或者空字符串
     *
     * @param expression 表达式，当为true时添加条件
     * @param column     数据库字段名
     * @return 返回Query对象
     */
    default T isEmpty(boolean expression, String column) {
        if (expression) {
            isEmpty(column);
        }
        return (T) this;
    }

    /**
     * 添加1=2条件
     *
     * @return 返回Query对象
     */
    default T oneEqTwo() {
        return this.sql("1=2");
    }

    /**
     * 根据表达式添加1=2条件
     *
     * @param expression 表达式，当为true时添加条件
     * @return 返回Query对象
     */
    default T oneEqTwo(boolean expression) {
        if (expression) {
            oneEqTwo();
        }
        return (T) this;
    }

    /**
     * 使用key/value进行多个等于的比对,相当于多个eq的效果
     *
     * @param map 键值对
     * @return 返回Query对象
     */
    default T allEq(LinkedHashMap<String, Object> map) {
        getCondition().allEq(map);
        return (T) this;
    }

    /**
     * 根据表达式添加使用key/value进行多个等于的比对,相当于多个eq的效果
     *
     * @param expression 表达式，当为true时添加条件
     * @param map        键值对
     * @return 返回Query对象
     */
    default T allEq(boolean expression, LinkedHashMap<String, Object> map) {
        if (expression) {
            allEq(map);
        }
        return (T) this;
    }

}
